<template>
  <div class="audio-management">
    <div class="header">
      <a-button type="primary" @click="handleAdd">添加</a-button>
    </div>
    <a-table
      :columns="columns"
      :data-source="audioFiles"
      :row-selection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
      :pagination="pagination"
      :loading="loading"
      @change="handleTableChange"
    >
      <template #bodyCell="{ column, record }">
        <template v-if="column.key === 'name'">
          {{ record.name }}
        </template>
        <template v-else-if="column.key === 'action'">
          <div class="action-buttons">
            <a-button type="link" @click="handlePlay(record)">
              <template #icon><play-circle-outlined /></template>
            </a-button>
            <a-button type="link" @click="handlePause(record)">
              <template #icon><pause-circle-outlined /></template>
            </a-button>
            <a-button type="link" @click="handleDownload(record)">
              <template #icon><download-outlined /></template>
            </a-button>
            <a-button type="link" @click="handleDelete(record)">
              <template #icon><delete-outlined /></template>
            </a-button>
          </div>
        </template>
      </template>
    </a-table>
    <a-modal
      v-model:visible="modalVisible"
      title="添加音频文件"
      :confirm-loading="uploading"
      @ok="handleModalOk"
      @cancel="handleModalCancel"
    >
      <a-upload
        v-model:file-list="fileList"
        :before-upload="beforeUpload"
        :multiple="false"
        :disabled="uploading"
      >
        <a-button :disabled="uploading">
          <upload-outlined />
          选择文件
        </a-button>
      </a-upload>
      <div v-if="uploading" class="upload-progress">
        <a-progress :percent="uploadProgress" :status="uploadProgressStatus" />
        <div class="upload-progress-text">{{ uploadStatusText }}</div>
      </div>
    </a-modal>
  </div>
</template>
<script setup>
import { ref, onMounted, computed } from 'vue'
import { message, Modal } from 'ant-design-vue'
import { getAudioList, playAudio, downloadAudio, deleteAudio, uploadAudio, stopAudio } from '@/api/audio'
import {
  PlayCircleOutlined,
  DownloadOutlined,
  DeleteOutlined,
  UploadOutlined,
  PauseCircleOutlined
} from '@ant-design/icons-vue'
import SparkMD5 from 'spark-md5'

const columns = [
  {
    title: '名称',
    dataIndex: 'name',
    key: 'name',
  },
  {
    title: '操作',
    key: 'action',
    width: 200,
  }
]

const audioFiles = ref([])
const selectedRowKeys = ref([])
const modalVisible = ref(false)
const fileList = ref([])
const loading = ref(false)
const pagination = ref({
  current: 1,
  pageSize: 10,
  total: 0,
  showSizeChanger: true,
  pageSizeOptions: ['10', '20', '50'],
  showTotal: (total) => `总共 ${total} 项`
})

// 格式化文件大小
const formatSize = (size) => {
  if (!size) return '-'
  
  const units = ['B', 'KB', 'MB', 'GB']
  let i = 0
  while (size >= 1024 && i < units.length - 1) {
    size /= 1024
    i++
  }
  return `${size.toFixed(2)} ${units[i]}`
}

// 加载音频列表
const fetchAudioList = async () => {
  loading.value = true
  try {
    const params = {
      page: pagination.value.current,
      page_size: pagination.value.pageSize
    }
    
    const data = await getAudioList(params)
    
    // 根据协议格式处理返回数据
    if (data && data.result && data.result.audio_files) {
      audioFiles.value = data.result.audio_files.map(item => ({
        ...item,
        key: item.id
      }))
      pagination.value.total = data.result.total || 0
    } else {
      audioFiles.value = []
    }
  } catch (error) {
    console.error('获取音频列表失败:', error)
    message.error(`获取音频列表失败: ${error.message || '未知错误'}`)
    audioFiles.value = []
  } finally {
    loading.value = false
  }
}

// 表格分页、排序、筛选变化时触发
const handleTableChange = (pag) => {
  pagination.value.current = pag.current
  pagination.value.pageSize = pag.pageSize
  fetchAudioList()
}

const onSelectChange = (keys) => {
  selectedRowKeys.value = keys
}

const handleAdd = () => {
  modalVisible.value = true
}

const handlePlay = async (record) => {
  try {
    await playAudio(record.id)
    message.success(`正在播放: ${record.name}`)
  } catch (error) {
    console.error('播放音频失败:', error)
    message.error(`播放音频失败: ${error.message || '未知错误'}`)
  }
}

const handlePause = async (record) => {
  try {
    await stopAudio(record.id)
    message.info(`已暂停: ${record.name}`)
  } catch (error) {
    console.error('暂停音频失败:', error)
    message.error(`暂停音频失败: ${error.message || '未知错误'}`)
  }
}

const handleDownload = async (record) => {
  try {
    // 显示下载中状态
    message.loading({ content: '准备下载...', key: 'download' });
    
    const blob = await downloadAudio(record.id);
    
    // 验证文件类型
    if (!blob.type.startsWith('audio/')) {
      throw new Error('下载的文件不是有效的音频文件');
    }
    
    // 创建下载链接
    const url = window.URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url;
    link.download = record.name;
    
    // 执行下载
    document.body.appendChild(link);
    link.click();
    
    // 清理
    document.body.removeChild(link);
    window.URL.revokeObjectURL(url);
    
    message.success({ content: '下载完成', key: 'download' });
  } catch (error) {
    console.error('下载音频失败:', error);
    message.error({ 
      content: `下载失败: ${error.message || '未知错误'}`, 
      key: 'download',
      duration: 3 
    });
  }
}

const handleDelete = async (record) => {
  Modal.confirm({
    title: '确认删除',
    content: `确定要删除音频 "${record.name}" 吗？`,
    okText: '确认',
    cancelText: '取消',
    onOk: async () => {
      try {
        await deleteAudio(record.id)
        message.success(`已删除: ${record.name}`)
        fetchAudioList() // 刷新列表
      } catch (error) {
        console.error('删除音频失败:', error)
        message.error(`删除音频失败: ${error.message || '未知错误'}`)
      }
    }
  })
}

// 上传相关状态
const uploading = ref(false)
const uploadProgress = ref(0)
const uploadStatusText = ref('')
const uploadCurrentChunk = ref(0)
const uploadTotalChunks = ref(0)
const uploadAudioId = ref(null)
const chunkSize = 64 * 1024 // 64KB 块大小

// 上传进度状态
const uploadProgressStatus = computed(() => {
  if (uploadProgress.value === 100) return 'success'
  return 'active'
})

// 分块读取文件内容为 base64
const readFileChunk = (file, start, end) => {
  return new Promise((resolve) => {
    const reader = new FileReader()
    reader.onload = (e) => {
      // 返回 base64 字符串，去掉头部的 data:xxx;base64,
      const base64 = e.target.result.split(',')[1]
      resolve(base64)
    }
    const blob = file.slice(start, end)
    reader.readAsDataURL(blob)
  })
}

// 计算文件的 MD5
const calculateFileMD5 = (file) => {
  return new Promise((resolve) => {
    const chunkSize = 2097152 // 2MB 分块读取
    const chunks = Math.ceil(file.size / chunkSize)
    let currentChunk = 0
    const spark = new SparkMD5.ArrayBuffer()
    
    const fileReader = new FileReader()
    
    fileReader.onload = (e) => {
      spark.append(e.target.result) // 追加数组缓冲区
      currentChunk++
      
      if (currentChunk < chunks) {
        loadNext()
      } else {
        resolve(spark.end()) // 完成后返回结果
      }
    }
    
    fileReader.onerror = () => {
      console.error('文件读取错误')
      resolve(null)
    }
    
    function loadNext() {
      const start = currentChunk * chunkSize
      const end = start + chunkSize >= file.size ? file.size : start + chunkSize
      fileReader.readAsArrayBuffer(file.slice(start, end))
    }
    
    loadNext()
  })
}

// 获取音频文件的时长
const getAudioDuration = (file) => {
  return new Promise((resolve) => {
    const audioElement = new Audio()
    const objectUrl = URL.createObjectURL(file)
    
    audioElement.addEventListener('loadedmetadata', () => {
      // 获取音频时长（秒）
      const duration = audioElement.duration
      URL.revokeObjectURL(objectUrl)
      resolve(isNaN(duration) ? 0 : duration)
    })
    
    audioElement.addEventListener('error', () => {
      URL.revokeObjectURL(objectUrl)
      console.error('获取音频时长失败')
      resolve(0)
    })
    
    audioElement.src = objectUrl
  })
}

// 上传文件
const uploadFile = async (file) => {
  try {
    uploading.value = true
    uploadProgress.value = 0
    uploadStatusText.value = '准备上传...'
    
    // 计算文件的 MD5 值
    uploadStatusText.value = '计算文件特征值...'
    const md5 = await calculateFileMD5(file)
    
    // 获取音频时长
    uploadStatusText.value = '获取音频信息...'
    const duration = await getAudioDuration(file)
    
    // 计算需要分成多少块上传
    const totalChunks = Math.ceil(file.size / chunkSize)
    uploadCurrentChunk.value = 0
    uploadTotalChunks.value = totalChunks
    
    // 准备文件信息
    const fileInfo = {
      name: file.name,
      size: file.size,
      type: file.type,
      md5: md5,
      duration: Math.round(duration)
    }
    
    // 逐块上传
    for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
      if (!uploading.value) break // 如果用户取消了上传
      
      uploadCurrentChunk.value = chunkIndex
      const start = chunkIndex * chunkSize
      const end = Math.min(file.size, start + chunkSize)
      
      uploadStatusText.value = `正在上传第 ${chunkIndex + 1}/${totalChunks} 块...`
      
      // 读取文件块并转换为 base64
      const chunkData = await readFileChunk(file, start, end)
      
      // 上传当前块
      const uploadParams = {
        chunkIndex: chunkIndex,
        totalChunks: totalChunks,
        chunkData: chunkData
      }
      
      // 仅在上传第一块时提供文件信息
      if (chunkIndex === 0) {
        uploadParams.fileInfo = fileInfo
      }
      
      const result = await uploadAudio(uploadParams)
      
      // 更新进度
      uploadProgress.value = Math.round(((chunkIndex + 1) / totalChunks) * 100)
      
      // 保存音频ID (上传完成时返回)
      if (result && result.audio_id) {
        uploadAudioId.value = result.audio_id
      }
    }
    
    uploadStatusText.value = '上传完成'
    message.success('音频文件上传成功')
    return true
  } catch (error) {
    console.error('音频上传失败:', error)
    message.error(`上传失败: ${error.message || '未知错误'}`)
    return false
  } finally {
    uploading.value = false
  }
}

const beforeUpload = (file) => {
  const isAudio = file.type.startsWith('audio/')
  if (!isAudio) {
    message.error('只能上传音频文件!')
    return false
  }
  const isLt100M = file.size / 1024 / 1024 < 100
  if (!isLt100M) {
    message.error('音频文件不能超过 100MB!')
    return false
  }
  return false // 返回false阻止默认上传行为
}

const handleModalOk = async () => {
  if (fileList.value.length === 0) {
    message.warning('请先选择要上传的音频文件')
    return
  }
  
  try {
    const file = fileList.value[0].originFileObj
    const success = await uploadFile(file)
    
    if (success) {
      modalVisible.value = false
      fileList.value = []
      fetchAudioList() // 刷新列表
    }
  } catch (error) {
    console.error('上传处理失败:', error)
    message.error(`上传处理失败: ${error.message || '未知错误'}`)
  }
}

const handleModalCancel = () => {
  if (uploading.value) {
    Modal.confirm({
      title: '确认取消',
      content: '文件正在上传中，确定要取消上传吗？',
      okText: '确认',
      cancelText: '继续上传',
      onOk: () => {
        uploading.value = false
        modalVisible.value = false
        fileList.value = []
      }
    })
  } else {
    modalVisible.value = false
    fileList.value = []
  }
}

// 组件挂载时加载音频列表
onMounted(() => {
  fetchAudioList()
})
</script>
<style scoped>
.audio-management {
  padding: 24px;
}
.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
}
.title {
  font-size: 16px;
  font-weight: 500;
}
.action-buttons {
  display: flex;
  gap: 8px;
}
.action-buttons .ant-btn {
  padding: 4px 8px;
}
:deep(.ant-upload-list) {
  margin-top: 16px;
}
.upload-progress {
  margin-top: 16px;
}
.upload-progress-text {
  margin-top: 8px;
  color: rgba(0, 0, 0, 0.45);
}
</style>